<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖和截流的测试</title>
    <style>
        pre {
            text-align: center;
        }

        div {
            height: 100px;
            border: 1px solid gray;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        span {
            padding: 20px;
        }
    </style>
</head>

<body>
    <pre>
        窗口的 resize、scroll,输入框内容校验等操作时，
        如果这些操作处理函数较为复杂或页面频繁重渲染等操作时，
        如果事件触发的频率无限制，会加重浏览器的负担，导致用户体验非常糟糕。
        此时我们可以采用debounce（防抖）和throttle（节流）的方式来减少触发的频率，
        同时又不影响实际效果。
    </pre>
    <pre>
        1、防抖：指的是一段时间内，只触发一次函数的执行。每当再次调用时，会重新计时
        2、节流：指的是，在一段时间内。不管点击多少次，都只执行一次函数。这里不会重新计时
    </pre>
    <!-- 防抖的例子 -->
    <div class="debounce">
        <span>防抖的例子</span>
        <input type="text" id="text">
        <span class="debounce-tips"></span>
    </div>
    <!-- 节流 -->
    <div class="throttle">
        <span>节流的例子</span>
        <button >点我试试节流</button>
        <span class="tips"></span>
    </div>


    <script>
        const input = document.querySelector('input');
        const button = document.querySelector('button');
        const debounceTip = document.querySelector('.debounce-tips');
        const tips = document.querySelector('.tips');

        /**
         * 防抖函数1
         * 自定义变量的实现方式
         */

        function debounce(func, delay) {
            //想要实现某一时间段内只执行一次函数，那么就要用setTimeout
            // 想要实现某一时间只执行一次，那么想到，再次点击，就要将之前的计时清除
            // 那么就要记录一下定时器，并且每次进入的时候清除上一次的,那么代码就写成这样
            //  let timer;
            //  clearTimeout(timer)
            //  timer = setTimeout(func(),delay);
            //但是这样很明显不能满足，因为timer永远都是undefined。那么怎么办？我还想保存起来，
            //还得保证这样的顺序，所以需要用函数闭包
            let timer;
            return function (...args) {
                if (timer) {
                    clearTimeout(timer);
                }
                timer = setTimeout(() => {
                    func.call(this, ...args);
                    timer = null;
                }, delay || 500);
            }
        }

        /**
         * 防抖加强版，可以直接调用的那种
         * 将计时器放在函数身上
         */
        function debouncePro(fn, delay) {
            return function () {
                let args = arguments;
                clearTimeout(fn.id);
                fn.id = setTimeout(() => {
                    fn(...args);
                    delete fn.id
                }, delay || 500);
            }
        }


        /**
         * 打印输入的内容
         */
        function printInputValue(value) {
            debounceTip.innerText = value;
        }

        /*这里注意一定要用变量接一下，切记不可以直接调用debounce(printInputValue, 1000)*/
        // 如果直接调用，那么每次返回的是一个新的函数。那就失去了闭包的意义
        let debounceRet = debounce(printInputValue, 1000);

        input.addEventListener('keyup', function (event) {
            // 调用防抖函数--注意千万不要用下面的这种方式调用，这样会导致防抖无效
            // 因为每次返回的都是新的函数，那么定时器就清理不掉
            // debounce(printInputValue, 3000)(event.target.value);
            // debounceRet(event.target.value);

            // 这个也OK
            debouncePro(printInputValue, 1000)(event.target.value);
        });


        
        // 节流的实现
        function throttle(func,delay) {
            let timer;
            return function(...args){
                if(timer) return
                timer = setTimeout(()=>{
                    func(...args);
                    timer = null;
                },delay || 1000);
            }     
        }

        //展示节流的提示
        let throRet = throttle(()=>{tips.innerText = `别催我，已经在加油了！${count}`; count ++});
        let count = 0;
        // 节流测试
        function testThrottle(){
            throRet(count);
        }

        button.addEventListener('click',function(e){
            testThrottle();
        })
    </script>
</body>

</html>